{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 文件的打开与关闭"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "不论是文本文件还是二进制文件，文件进行写入或读取操作，一般都可以分为以下三步：<br />\n",
    "（1）打开文件并创建文件对象；open()<br />\n",
    "（2）通过文件对象对文件中的内容进行读取和写入等操作；<br />\n",
    "（3）关闭并保存文件内容。close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fr = open(file, mode='r', encoding=None)  # fr为变量名，是用户为文件对象所命名字\n",
    "fr.close()                                # 关闭所创建的文件对象，fr为文件对象名"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "内容管理器由关键字“with”和“as”联合启动，将文件打开操作置于内容管理器中，不需要用f.close()显式的关闭文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open(file, mode='r', encoding=None) as fr:  # fr为变量名，是用户为文件对象所命名字\n",
    "    pass                                         # 在缩进区域写对文件对象进行操作的语句"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "file 参数是一个带路径的文件名:<br />\n",
    "\n",
    "### 绝对路径:<br />\n",
    "从根目录开始,如'c:\\\\temp\\\\temp.txt'<br />\n",
    "\n",
    "### 相对路径：  \n",
    "相对当前文件位置的路径，如：  \n",
    "./temp.txt （.表示当前目录，..表示上级目录）<br />\n",
    "../data/temp.txt （..表示上级目录，../data/表示当前文件上级目录的子目录，即当前文件同级的子目录）<br />\n",
    "\n",
    "当打开的文件与当前程序文件在同一路径下时，不需要写路径，一般建议使用相对路径。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用绝对路径时，若反斜杠与后面字符可构成转义字符时，需使用两个反斜杠表示。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "'c:\\temp\\next.txt'\n",
    "print('c:\\temp\\next.txt')\n",
    "# 输出结果为： \n",
    "# c:\temp\n",
    "# ext.txt\n",
    "\n",
    "# “\\t”是转义字符，所以需要写成\n",
    "'c:\\\\temp\\\\next.txt'\n",
    "print('c:\\\\temp\\\\next.txt')  # 输出结果为： c:\\temp\\next.txt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "或是在路径字符串前面加“r”，明确告诉编译器这个字符串是个原生字符串，不要转义，从而避免解析错误。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('c:\\temp\\next.txt')  \n",
    "# 输出结果为： \n",
    "# c:\temp\n",
    "# ext.txt\n",
    "\n",
    "# 前面加r构建原生字符串，不转义\n",
    "print(r'c:\\temp\\next.txt')  # 输出结果为： c:\\temp\\next.txt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "mode 参数是可选参数，用于指定文件打开的方式和类型  \n",
    "该参数可以使用的符号包括：  \n",
    "'r'、'w'、'x'、'a'、'b'、't'、'+'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 符号 | 含义 |\n",
    "| :---- | :---- |\n",
    "| 'r' | 以只读模式打开文件（默认值） |\n",
    "| 'w' | 以写数据模式打开文件，该文件已存在，先清除该文件中所有内容；该文件不存在，先创建该文件再打开。 |\n",
    "| 'x' | 以创建文件写数据模式打开文件，该文件已存在，打开失败。 |\n",
    "| 'a' | 以追加写数据模式打开文件，该文件已存在，新数据追加在现有数据之后；该文件不存在，先创建文件后在打开。 |\n",
    "| 'b' | 以二进制模式打开文件处理数据 |\n",
    "| 't' | 以文本模式打开文件处理数据（默认模式） |\n",
    "| '+' | 打开文件并允许更新，相当于增加读或写模式（与 <font color='red'>'r'、'w' 或 'a'   组合使用</font>，如  'r+'可读可写、'w+'可写可读、'a+'可追加写，可读） |\n"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "1. mode 参数缺省时使用默认值'r'，以只读方式打开。\n",
    "2. encoding 参数缺省时时使用当前操作系统默认编码类型（中文 windows10 一般默认 GBK 编码，Mac 和Linux等一般默认编码为UTF-8 编码）  \n",
    "   用二进制对象返回文件内容时，encoding 参数不可用。"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "读取\"What is New in Python3.11.txt\"文件内容："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[What is New in Python3.11.txt](https://data.educoder.net/api/attachments/3391615?type=text/plain)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "new = open('/data/bigfiles/What is New in Python3,11.txt')  # 以读模式打开文件，创建文件对象，命名为new\n",
    "print(new.read())  # 读文件为字符串输出\n",
    "new.close()        # 关闭文件对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open('/data/bigfiles/What is New in Python3,11.txt') as new:  # 以读模式打开文件，创建文件对象，命名为new\n",
    "    print(new.read())  # 读文件为字符串输出\n",
    "    \n",
    "# 退出缩进时自动关闭文件"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "读取并输出文件“9.1 出塞.txt”中的内容"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[9.1 出塞.txt](https://data.educoder.net/api/attachments/3391631?type=text/plain)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "fr = open('/data/bigfiles/9,1 出塞.txt', 'r', encoding='utf-8')  # 打开文件创建文件对象，命名为fr\n",
    "print(fr.read())  # 读文件为字符串输出\n",
    "fr.close()        # 关闭文件对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "fr = open('/data/bigfiles/9,1 出塞.txt', 'r', encoding='utf-8')  # 打开文件创建文件对象，命名为fr\n",
    "for line in fr:          # 对文件对象进行逐行遍历\n",
    "    print(line)            # 行末的换行符会输出一个空行\n",
    "fr.close()                # 关闭文件对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "fr = open('/data/bigfiles/9,1 出塞.txt', 'r', encoding='utf-8')  # 打开文件创建文件对象，命名为fr\n",
    "for line in fr:          # 对文件对象进行逐行遍历\n",
    "    print(line.strip())  # line.strip()函数去掉行末的换行符，消除空行\n",
    "fr.close()                # 关闭文件对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 用上下文管理器实现，不需要显示关闭文件，避免异常\n",
    "\n",
    "with open('/data/bigfiles/9,1 出塞.txt','r',encoding = 'utf-8') as poem:  # 打开文件创建文件对象，命名为poem\n",
    "    print(poem.read())  # 读文件为字符串输出"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 用上下文管理器实现，不需要显示关闭文件，避免异常\n",
    "\n",
    "with open('/data/bigfiles/9,1 出塞.txt','r',encoding = 'utf-8') as poem:  # 打开文件创建文件对象，命名为poem\n",
    "    for line in poem:          # 对文件对象进行逐行遍历\n",
    "        print(line.strip())  # line.strip()函数去掉行末的换行符，消除空行"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "建议将读文件的代码定义为函数，以方便修改和维护代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def open_file(file):  \n",
    "    \"\"\"接收表示文件名的字符串变量，打开文件，遍历读取文件并输出其内容\"\"\"\n",
    "    with open(file,'r',encoding = 'utf-8') as poem:  # 打开文件创建文件对象，命名为poem\n",
    "        for line in poem:          # 对文件对象进行逐行遍历\n",
    "            print(line.strip())  # line.strip()函数去掉行末的换行符，消除空行\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    filename = '/data/bigfiles/9,1 出塞.txt'  # 文件名定义变量，方便修改\n",
    "    open_file(filename)        # 调用函数读取并输出文件内容"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[What is New in Python3.11.txt](https://data.educoder.net/api/attachments/3391615?type=text/plain)  \n",
    "[9.1 出塞.txt](https://data.educoder.net/api/attachments/3391631?type=text/plain)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
